package com.goldsprite.gdxcore.gfsm;

import java.util.ArrayList;
import java.util.List;

public class StateMachine {
	public boolean isState(Class<? extends State> stateClazz) {
		if(currentState == null) return false;
		return stateClazz.isAssignableFrom(currentState.getClass());
	}

	private static class StateInfo {
		State state;
		int priority;

		StateInfo(State state, int priority) {
			this.state = state;
			this.priority = priority;
		}
	}

	private State currentState, defaultState;
	private final List<StateInfo> states = new ArrayList<>();
	private final Entity entity;
	private final FsmInput input;

	public StateMachine(Entity entity, FsmInput input) {
		this.entity = entity;
		this.input = input;
		initializeStates();
	}

	private void initializeStates() {
	}

	public void registerState(State state, int priority) {
		state.setFsm(this);
		states.add(new StateInfo(state, priority));
		if(currentState == null){
			defaultState = currentState = state;
			chageState(state);
		}
	}

	private void chageState(State state) {
		if(currentState != null) currentState.exit();
		currentState = state;
		currentState.enter();
	}

	public void update() {
		if (currentState != null) {
			StateInfo nextStateInfo = findNextState();

			if (nextStateInfo != null) {
				chageState(nextStateInfo.state);
			}

			currentState.running();
		}
	}

	private StateInfo findNextState() {
		StateInfo bestStateInfo = null;
		int bestPriority = -1;
		if(!currentState.canExit()) bestPriority = getCurrentStatePriority(currentState);

		for (StateInfo stateInfo : states) {
			if(stateInfo.state == currentState) continue;
			if (stateInfo.priority >= bestPriority && stateInfo.state.canEnter()) {
				bestStateInfo = stateInfo;
				bestPriority = stateInfo.priority;
			}
		}

		return bestStateInfo;
	}

	private int getCurrentStatePriority(State state) {
		StateInfo stateInfo = states.stream().filter(i -> i.state == state).findFirst().orElse(null);
		if(stateInfo == null) return -1;
		return stateInfo.priority;
	}

	// Getter 方法供状态类访问
	public Entity getEntity() {
		return entity;
	}

	public FsmInput getInput() {
		return input;
	}
}
